package com.admin_system.service.impl;

import com.admin_system.mapper.MaterialMapper;
import com.admin_system.pojo.Material;
import com.admin_system.service.MaterialService;
import com.admin_system.utils.UserUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 物料服务实现类
 */
@Service
public class MaterialServiceImpl implements MaterialService {

    private static final Logger logger = LoggerFactory.getLogger(MaterialServiceImpl.class);
    
    @Value("${file.upload-dir:src/main/resources/static/uploads/materials}")
    private String uploadDir;
    
    /**
     * 用于Web访问的相对路径（相对于static目录）
     */
    private static final String WEB_ACCESS_PATH = "/uploads/materials";
    
    @Autowired
    private MaterialMapper materialMapper;
    
    @Override
    public List<Material> getAllMaterials() {
        return materialMapper.selectAll();
    }
    
    @Override
    public Material getMaterialById(Long id) {
        return materialMapper.selectById(id);
    }
    
    @Override
    public Material saveMaterial(MultipartFile file, String description) throws Exception {
        if (file.isEmpty()) {
            throw new Exception("无法保存空文件");
        }
        
        // 获取当前登录用户
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        
        // 使用真实姓名代替用户名
        String realName = UserUtils.getRealNameByUsername(username);
        
        // 创建文件存储路径
        Path uploadPath = Paths.get(uploadDir);
        if (!Files.exists(uploadPath)) {
            Files.createDirectories(uploadPath);
            logger.info("创建上传目录: {}", uploadPath.toAbsolutePath());
        }
        
        // 生成唯一文件名避免冲突
        String originalFilename = file.getOriginalFilename();
        String extension = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        
        // 使用当前时间戳和随机UUID，确保文件名唯一且有序
        String timestamp = String.valueOf(System.currentTimeMillis());
        String newFilename = timestamp + "_" + UUID.randomUUID().toString().substring(0, 8) + extension;
        Path filePath = uploadPath.resolve(newFilename);
        
        // 保存文件
        try {
            logger.info("保存文件: {} 到 {}", originalFilename, filePath);
            Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            logger.error("保存文件失败: {}", e.getMessage(), e);
            throw new Exception("保存文件时发生错误: " + e.getMessage());
        }
        
        // 创建物料记录
        Material material = new Material();
        material.setFileName(originalFilename);
        material.setFilePath(newFilename);
        material.setDescription(description);
        material.setFileType(file.getContentType());
        material.setFileSize(file.getSize());
        material.setUploadTime(new Date());
        material.setUploadUser(realName); // 使用真实姓名
        material.setWebPath(WEB_ACCESS_PATH + "/" + newFilename);
        
        // 保存到数据库
        materialMapper.insert(material);
        logger.info("物料记录已保存到数据库, ID: {}, 文件名: {}, 上传者: {}", material.getId(), originalFilename, realName);
        
        return material;
    }
    
    @Override
    public Map<String, Object> getMaterialFile(Long id) throws Exception {
        // 获取物料记录
        Material material = materialMapper.selectById(id);
        if (material == null) {
            logger.warn("文件不存在, ID: {}", id);
            throw new Exception("文件不存在");
        }
        
        // 构建文件路径
        Path filePath = Paths.get(uploadDir).resolve(material.getFilePath());
        Resource resource;
        
        try {
            resource = new UrlResource(filePath.toUri());
            if (!resource.exists() || !resource.isReadable()) {
                logger.error("无法读取文件: {}, 路径: {}", material.getFileName(), filePath);
                throw new Exception("无法读取文件: " + material.getFileName());
            }
        } catch (MalformedURLException e) {
            logger.error("无效的文件路径: {}", e.getMessage(), e);
            throw new Exception("无效的文件路径: " + e.getMessage());
        }
        
        Map<String, Object> result = new HashMap<>();
        result.put("resource", resource);
        result.put("filename", material.getFileName());
        
        return result;
    }
    
    @Override
    public void deleteMaterial(Long id) throws Exception {
        // 获取物料记录
        Material material = materialMapper.selectById(id);
        if (material == null) {
            logger.warn("要删除的文件不存在, ID: {}", id);
            throw new Exception("文件不存在");
        }
        
        // 删除物理文件
        boolean fileDeleted = false;
        String filePath = material.getFilePath();
        String fullPath = uploadDir + "/" + filePath;
        
        // 记录详细的文件路径信息用于调试
        logger.info("尝试删除物料文件: ID={}, 相对路径={}, 完整路径={}", id, filePath, fullPath);
        
        // 先使用Java NIO API尝试删除
        try {
            Path path = Paths.get(uploadDir).resolve(filePath);
            logger.info("尝试删除文件: {}", path.toAbsolutePath());
            
            if (Files.exists(path)) {
                Files.delete(path);
                fileDeleted = true;
                logger.info("文件已成功删除(NIO): {}", path.toAbsolutePath());
            } else {
                logger.warn("文件不存在，无法删除(NIO): {}", path.toAbsolutePath());
            }
        } catch (IOException e) {
            logger.warn("使用NIO删除文件失败: {}", e.getMessage());
            
            // 如果NIO方法失败，尝试使用File API删除
            try {
                File file = new File(fullPath);
                if (file.exists()) {
                    if (file.delete()) {
                        fileDeleted = true;
                        logger.info("文件已成功删除(File API): {}", fullPath);
                    } else {
                        logger.warn("使用File API删除文件失败: {}", fullPath);
                    }
                } else {
                    logger.warn("文件不存在，无法删除(File API): {}", fullPath);
                }
            } catch (Exception ex) {
                logger.error("使用File API删除文件发生异常: {}", ex.getMessage(), ex);
                // 即使文件删除失败，也继续删除数据库记录
            }
        }
        
        // 删除数据库记录
        materialMapper.deleteById(id);
        
        // 记录删除结果
        if (fileDeleted) {
            logger.info("物料已完全删除(文件和数据库记录): ID={}, 文件名={}", id, material.getFileName());
        } else {
            logger.warn("仅删除了数据库记录，物理文件可能未删除: ID={}, 文件名={}", id, material.getFileName());
        }
    }
    
    @Override
    public Map<String, Integer> cleanupOrphanedFiles() throws Exception {
        logger.info("开始清理孤立的物料文件");
        
        // 统计成功和失败的数量
        int successCount = 0;
        int failedCount = 0;
        
        try {
            // 获取所有数据库中的文件路径
            List<Material> allMaterials = materialMapper.selectAll();
            Map<String, Long> dbFilePaths = new HashMap<>();
            
            for (Material material : allMaterials) {
                dbFilePaths.put(material.getFilePath(), material.getId());
            }
            
            logger.info("数据库中有 {} 个物料记录", dbFilePaths.size());
            
            // 获取物理目录中的所有文件
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                logger.info("上传目录不存在: {}", uploadPath);
                return Map.of("success", 0, "failed", 0);
            }
            
            // 遍历上传目录中的所有文件
            try (var files = Files.list(uploadPath)) {
                List<Path> physicalFiles = files.collect(java.util.stream.Collectors.toList());
                logger.info("磁盘上有 {} 个文件", physicalFiles.size());
                
                for (Path file : physicalFiles) {
                    String fileName = file.getFileName().toString();
                    
                    // 跳过目录和非物料文件
                    if (Files.isDirectory(file) || fileName.startsWith(".")) {
                        continue;
                    }
                    
                    // 检查该文件是否在数据库中有记录
                    if (!dbFilePaths.containsKey(fileName)) {
                        logger.info("发现孤立文件: {}", fileName);
                        
                        // 删除孤立文件
                        try {
                            Files.delete(file);
                            logger.info("成功删除孤立文件: {}", fileName);
                            successCount++;
                        } catch (IOException e) {
                            logger.error("删除孤立文件失败: {}, 错误: {}", fileName, e.getMessage());
                            
                            // 尝试使用File API删除
                            try {
                                File fileObj = file.toFile();
                                if (fileObj.delete()) {
                                    logger.info("使用File API成功删除孤立文件: {}", fileName);
                                    successCount++;
                                } else {
                                    logger.error("使用File API删除孤立文件失败: {}", fileName);
                                    failedCount++;
                                }
                            } catch (Exception ex) {
                                logger.error("使用File API删除孤立文件发生异常: {}, 错误: {}", fileName, ex.getMessage());
                                failedCount++;
                            }
                        }
                    }
                }
            }
            
            logger.info("清理孤立文件完成。成功: {}, 失败: {}", successCount, failedCount);
            
        } catch (Exception e) {
            logger.error("清理孤立文件过程中发生异常: {}", e.getMessage(), e);
            throw new Exception("清理孤立文件失败: " + e.getMessage());
        }
        
        return Map.of("success", successCount, "failed", failedCount);
    }
} 